home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
9-Digit Zip Code Directory
/
9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO
/
z4src.zip
/
DIINDEX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-29
|
12KB
|
408 lines
//----------------------------------------------------------------------------
// MODULE DESCRIPTION
//
// Module: diisam.c
// Title: Data File I/O Library
// Notice: John M. Weeder
// Copyright (c) 1993. All rights reserved.
// This module contains proprietary information and should be
// treated as confidential.
//
//----------------------------------------------------------------------------
// MAINTENANCE HISTORY
//
// $Workfile$
// $Revision$
// $Author$
// $Date$
// $Log$
//
//----------------------------------------------------------------------------
// MODULE NARRATIVE
//
//
// This module contains to generate an ISAM index file.
//
// THIS MODULE IS NOT RE-ENTRANT.
//
// The code in this module should be written entirely in C.
// Do not use any C++ constructs.
//
// This module is portable to:
// DOS 3.X+
// MS Windows 3.X+
// OS/2 2.X+
// OS/2 2.0 PM
// SCO UNIX.
//
// The following compilers are supported:
// MSC 6.0A
// MSC/C++ 7.0
// Borland C++ 3.1 for DOS
// Borland C++ 1.0 for OS/2 2.X
// SCO UNIX cc
//
//----------------------------------------------------------------------------
#include <di.h>
//----------------------------------------------------------------------------
// Globals
//----------------------------------------------------------------------------
typedef struct GI // Global data
{
HPF hpf; // Physical file handle
USHORT usBlockSize; // Block size of index
USHORT usBlockUsed; // Amount of current block used
LONG lBlocks; // Blocks in this logical file
PCSZ pcszLogical; // Logical file name
PFNINDEX pfnindex; // User index function
PBYTE pbBlock; // Pointer to block
LONG lTotalBlocks; // Total blocks
LONG lTotalSlack; // Total slack space
FPOS fpos; // Current file position
HF hf; // Output file handle
DI_INDEX di_index;
} GI;
static GI gi;
//----------------------------------------------------------------------------
// Prototypes
//----------------------------------------------------------------------------
static BOOL FN_L DioIndexBase(void);
static BOOL FN_L DioIndexDelete(void);
static BOOL FN_L DioIndexLevel(USHORT);
static BOOL FN_L DioIndexWrite(void);
//----------------------------------------------------------------------------
// Description: Create a multi-level ISAM index
// Parameters: pcsz Physical file name.
// File is opened, then closed when indexing is
// complete.
// pcszLogical Logical file to index
// pfnindex Indexing function
// cBlockSize Size of index block.
// If 0, use default size
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_E DioIndex(PCSZ pcsz, PCSZ pcszLogical, PFNINDEX pfnindex, USHORT usBlockSize)
{
BOOL fResult = FALSE;
USHORT usLevel = 0;
Assert(pcsz); // Validate data
Assert(pcszLogical);
Assert(pfnindex);
memset(&gi, 0, sizeof(gi)); // Set up global variables
gi.usBlockSize = usBlockSize >= sizeof(ISAMENTRY) ? usBlockSize: ISAM_BLOCK_SIZE;
gi.pcszLogical = pcszLogical;
gi.pfnindex = pfnindex;
Output( // Display information
"Indexing:\n"
" Physical file: %s\n"
" Logical file: %s\n",
pcsz, pcszLogical);
// Open physical file for writing
if (!DioOpenPhysical(pcsz, &gi.hpf, TRUE))
return FALSE;
// Delete existing indexes
if (!DioIndexDelete())
goto ERROR_EXIT;
// Allocate a data buffer
gi.pbBlock = MemAlloc(gi.usBlockSize);
if (gi.pbBlock == NULL)
goto ERROR_EXIT;
if (!DioIndexBase()) // Index data file
goto ERROR_EXIT;
while (gi.lBlocks > 1) // Index until Top level is a single
{ // block
usLevel++;
Assert(usLevel < ISAM_MAX_LEVEL);
if (!DioIndexLevel(usLevel))
goto ERROR_EXIT;
}
Output(
"Indexing complete.\n"
" %u levels.\n"
" %ld blocks totaling %ld (%u K) bytes.\n"
" %ld slack bytes (%u %%).\n"
"\n",
usLevel + 1,
gi.lTotalBlocks,
gi.lTotalBlocks * (LONG)gi.usBlockSize,
K(gi.lTotalBlocks * (LONG)gi.usBlockSize),
gi.lTotalSlack,
PERCENT(gi.lTotalSlack, gi.lTotalBlocks * (LONG)gi.usBlockSize));
fResult = TRUE;
ERROR_EXIT:
if (gi.pbBlock) // Free buffer
MemFree(gi.pbBlock);
DioClosePhysical(gi.hpf); // Close physical file
return fResult;
}
//----------------------------------------------------------------------------
// Description: Index the first level of the isam data file.
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
static BOOL FN_L DioIndexBase(void)
{
HLF hlf;
LONG i, lDataBlocks;
USHORT usDataBlockSize;
ISAMENTRY entry;
USHORT usKeyTotal;
BOOL fResult = FALSE;
BOOL fUserInit = FALSE;
PBYTE pbData = NULL;
// Open logical file
if (!DioOpenLogical(gi.pcszLogical, &hlf, DFT_ISAM_DATA))
return FALSE;
// Get block size and number of blocks
if (!DioGetBlockSize(hlf, &usDataBlockSize))
goto ERROR_EXIT;
pbData = MemAlloc((SIZET)usDataBlockSize);
if (pbData == NULL)
goto ERROR_EXIT;
if (!DioGetBlocks(hlf, &lDataBlocks))
goto ERROR_EXIT;
Output(
"Indexing base data file.\n"
" Block Size: %u\n"
" Total Blocks: %ld\n",
usDataBlockSize, lDataBlocks);
// Allocate data buffer
// Set up to append isam data
if (!DioAppend(HPF2PCSZ(gi.hpf), gi.pcszLogical, DFT_ISAM0,
gi.usBlockSize, &gi.hf, NULL))
goto ERROR_EXIT;
gi.fpos = FileGetPos(gi.hf); // Store position to append at
if (gi.fpos < 0)
goto ERROR_EXIT;
// Allow user to initialize
gi.di_index.lBlock = ISAM_START;
if (gi.pfnindex(&gi.di_index) == 0)
goto ERROR_EXIT;
fUserInit = TRUE;
// Set up index block buffer
memset(gi.pbBlock, 0, gi.usBlockSize);
gi.usBlockUsed = 0;
gi.lBlocks = 0;
gi.di_index.pbBlock = pbData;
gi.di_index.cbBlock = usDataBlockSize;
gi.di_index.pbKey = entry.bKey;
for (i = 0; i < lDataBlocks; ++i)
{
#if OS_UNIX
if ((i % 100) == 0)
Output(" Level 0 Blocks, Data %ld, Index %ld\n", i, gi.lBlocks);
#else
if ((i % 100) == 0)
Output("\r Level 0 Blocks, Data %ld, Index %ld", i, gi.lBlocks);
#endif
// Read block
if (!DioReadBlock(hlf, pbData, NULL, NULL))
goto ERROR_EXIT;
// Call user to get key
memset(&entry, 0, sizeof(entry));
gi.di_index.lBlock = i;
gi.di_index.cbKey = 0;
if (!gi.pfnindex(&gi.di_index))
goto ERROR_EXIT;
// Validate key
Assert(gi.di_index.cbKey && gi.di_index.cbKey <= ISAM_KEY_LEN);
usKeyTotal = (USHORT)(sizeof(entry) - ISAM_KEY_LEN + gi.di_index.cbKey);
if (gi.usBlockUsed + usKeyTotal > gi.usBlockSize)
{ // Write block if this key won't fit
if (!DioIndexWrite())
goto ERROR_EXIT;
}
entry.bSize = (BYTE)gi.di_index.cbKey;
entry.lBlock = i;
memcpy(gi.pbBlock + (SIZET)gi.usBlockUsed, &entry, usKeyTotal);
gi.usBlockUsed += (USHORT)usKeyTotal;
}
if (gi.usBlockUsed) // Write partial block if any
{
if (!DioIndexWrite())
goto ERROR_EXIT;
}
Output("\r Level 0 Blocks, Data %ld, Index %ld\n", i, gi.lBlocks);
if (!DioAppendClose(TRUE, TRUE)) // Update data file
goto ERROR_EXIT;
fResult = TRUE;
ERROR_EXIT:
if (fUserInit) // Allow user to clean up
{
memset(&gi.di_index, 0, sizeof(gi.di_index));
gi.di_index.lBlock = ISAM_END;
if (!gi.pfnindex(&gi.di_index))
fResult = FALSE;
}
if (pbData) // Free buffer
MemFree(pbData);
DioCloseLogical(hlf);
return fResult;
}
//----------------------------------------------------------------------------
// Description: Delete existing index files.
// Parameters: pcszLogical Logical file name
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
static BOOL FN_L DioIndexDelete(void)
{
SIZET i;
for (i = 0; i < ISAM_MAX_LEVEL; ++i)
if (DioIsLogicalFile(gi.pcszLogical, (USHORT)(DFT_ISAM0 + i)))
{
if (!DioDelete(HPF2PCSZ(gi.hpf), gi.pcszLogical, (USHORT)(DFT_ISAM0 + i)))
return FALSE;
Output(" Deleted existing index level %u\n", i);
}
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Index the first level of the isam data file.
// Parameters: usLevel ISAM level to index
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
static BOOL FN_L DioIndexLevel(USHORT usLevel)
{
HLF hlf;
USHORT usDataBlockSize;
LONG i, lDataBlocks;
PBYTE pbData = NULL;
PISAMENTRY pentry;
USHORT usKeyTotal;
BOOL fResult = FALSE;
// Open logical file
if (!DioOpenLogical(gi.pcszLogical, &hlf, (USHORT)(DFT_ISAM0 + usLevel - 1)))
return FALSE;
// Get block size
if (!DioGetBlockSize(hlf, &usDataBlockSize))
goto ERROR_EXIT;
Assert(usDataBlockSize == gi.usBlockSize);
// Get number of blocks
if (!DioGetBlocks(hlf, &lDataBlocks))
goto ERROR_EXIT;
pbData = MemAlloc((SIZET)usDataBlockSize);
if (pbData == NULL)
goto ERROR_EXIT;
Output(
"Indexing level %u.\n"
" Block Size: %u\n"
" Total Blocks: %ld\n",
usLevel,
usDataBlockSize, lDataBlocks);
pentry = (PISAMENTRY)pbData;
// Set up to append index
if (!DioAppend(HPF2PCSZ(gi.hpf), gi.pcszLogical, (USHORT)(DFT_ISAM0 + usLevel),
gi.usBlockSize, &gi.hf, NULL))
goto ERROR_EXIT;
gi.fpos = FileGetPos(gi.hf); // Get file position to append at
if (gi.fpos < 0)
goto ERROR_EXIT;
// Initialize index key buffer
memset(gi.pbBlock, 0, gi.usBlockSize);
gi.usBlockUsed = 0;
gi.lBlocks = 0;
for (i = 0; i < lDataBlocks; ++i)
{
#if OS_UNIX
if ((i % 100) == 0)
{
Output(" Level %u Blocks, Data %ld, Index %ld\n",
usLevel, i, gi.lBlocks);
}
#else
if ((i % 100) == 0)
{
Output("\r Level %u Blocks, Data %ld, Index %ld",
usLevel, i, gi.lBlocks);
}
#endif
if (!DioReadBlock(hlf, pbData, NULL, NULL))
goto ERROR_EXIT;
usKeyTotal = (USHORT)(sizeof(ISAMENTRY) - ISAM_KEY_LEN + (SIZET)pentry->bSize);
if (gi.usBlockUsed + usKeyTotal > gi.usBlockSize)
if (!DioIndexWrite())
goto ERROR_EXIT;
pentry->lBlock = i;
memcpy(gi.pbBlock + (SIZET)gi.usBlockUsed, pentry, usKeyTotal);
gi.usBlockUsed += (USHORT)usKeyTotal;
}
if (gi.usBlockUsed) // Write partial key
if (!DioIndexWrite())
goto ERROR_EXIT;
Output("\r Level %u Blocks, Data %ld, Index %ld\n",
usLevel, i, gi.lBlocks);
if (!DioAppendClose(TRUE, TRUE))
goto ERROR_EXIT;
fResult = TRUE;
ERROR_EXIT:
if (pbData) // Free buffer
MemFree(pbData);
DioCloseLogical(hlf);
return fResult;
}
//----------------------------------------------------------------------------
// Description: Write isam data to disk.
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
static BOOL FN_L DioIndexWrite(void)
{
if (!FileWrite(gi.hf, gi.pbBlock, (SIZET)gi.usBlockSize, gi.fpos))
return FALSE;
gi.lTotalBlocks++;
gi.lTotalSlack += (LONG)(gi.usBlockSize - gi.usBlockUsed);
gi.fpos += (FPOS)gi.usBlockSize;
memset(gi.pbBlock, 0, gi.usBlockSize);
gi.usBlockUsed = 0;
if (gi.lBlocks == 0x7FFFFFFFL)
{
Error("Maximum number of blocks exceeded.");
return FALSE;
}
gi.lBlocks++;
return TRUE;
}
//----------------------------------------------------------------------------
//------------------------------- End of File --------------------------------
//----------------------------------------------------------------------------